home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Programming Languages Suite
/
ProgramD2.iso
/
Borland
/
Borland C++ V5.02
/
OCFSRC.PAK
/
AUTOSYM.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1997-05-06
|
14KB
|
466 lines
//----------------------------------------------------------------------------
// ObjectComponents
// Copyright (c) 1994, 1997 by Borland International, All Rights Reserved
//
// $Revision: 2.4 $
//
// OLE Automation Server Implementation, except TServedObject (in typelib.cpp)
//----------------------------------------------------------------------------
#include <ocf/pch.h>
#if !defined(OCF_APPDESC_H)
# include <ocf/appdesc.h>
#endif
#if !defined(OCF_OCREG_H)
# include <ocf/ocreg.h>
#endif
#if !defined(OCF_OCCTRL_H) && defined(BI_PLAT_WIN32)
# include <ocf/occtrl.h>
#endif
#if defined(BI_NAMESPACE)
namespace OCF {
#endif
TAutoType TAutoVoid ::ClassInfo = {atVoid};
TAutoType TAutoByte ::ClassInfo = {atByte};
TAutoType TAutoShort ::ClassInfo = {atShort};
TAutoType TAutoLong ::ClassInfo = {atLong};
TAutoType TAutoFloat ::ClassInfo = {atFloat};
TAutoType TAutoDouble ::ClassInfo = {atDouble};
TAutoType TAutoCurrency ::ClassInfo = {atCurrency};
TAutoType TAutoDate ::ClassInfo = {atDatetime};
TAutoType TAutoString ::ClassInfo = {atString};
TAutoType TAutoBool ::ClassInfo = {atBool};
TAutoType TAutoUnknown ::ClassInfo = {atUnknown};
TAutoType TAutoDispatch ::ClassInfo = {atObject};
TAutoType TAutoVariant ::ClassInfo = {atVariant};
TAutoType TAutoSafeArray ::ClassInfo = {atSafeArray};
TAutoType TAutoShortRef ::ClassInfo = {atByRef|atShort};
TAutoType TAutoLongRef ::ClassInfo = {atByRef|atLong};
TAutoType TAutoFloatRef ::ClassInfo = {atByRef|atFloat};
TAutoType TAutoDoubleRef ::ClassInfo = {atByRef|atDouble};
TAutoType TAutoCurrencyRef::ClassInfo = {atByRef|atCurrency};
TAutoType TAutoDateRef ::ClassInfo = {atByRef|atDatetime};
TAutoType TAutoStringRef ::ClassInfo = {atByRef|atString};
TAutoType TAutoVariantRef ::ClassInfo = {atByRef|atVariant};
TAutoType TAutoBoolRef ::ClassInfo = {atByRef|atBool};
TAutoType TAutoByteRef ::ClassInfo = {atByRef|atByte};
void _OCFFUNC SendObituary(const void far* obj, const typeinfo& typeInfo)
{
TAppDescriptor* appDesc = NS_OCF::GetAppDescriptor();
if (appDesc)
appDesc->InvalidateObject(NS_OCF::MostDerived(obj, typeInfo));
}
#if defined(BI_NAMESPACE)
} // namespace OCF
#endif
//----------------------------------------------------------------------------
// TAutoClass implementation
//
TAutoClass::TClassList TAutoClass::ClassList = {0,0,0};// MUST BE MODULE GLOBAL
TAutoClass::TAutoClass(TAutoSymbol* table, TAutoSymbol* classSymbol,
const typeinfo& typeInfo, TAggregator aggregator)
: Table(table), ClassSymbol(classSymbol), TypeInfo(typeInfo),
Aggregator(aggregator), AutoIds (TRUE)
{
Type = atObject | atAutoClass;
NextClass = ClassList.List;
ClassList.List = this;
ClassList.Count++;
}
TAutoClass::~TAutoClass() // do we really need to support dynamic AutoClass?
{
for (TAutoClass** link = &ClassList.List; *link != 0; link = &(*link)->NextClass)
if (*link == this) {
*link = NextClass;
break;
}
}
short TAutoClass::CountCommands()
{
TAutoSymbol* sym;
if (!CommandCount) {
for (sym = Table; !sym->IsTerminator(); sym++) {
int attr = sym->GetFlags();
if (attr & asAnyCommand) {
CommandCount++;
if (attr & asOleType) {
if ((attr & asGetSet) == asGetSet)
VariableCount++;
else
FunctionCount++;
}
} else if (sym->TestFlag(asClass)) {
TAutoClass* cls = sym->GetClass();
if (!sym->SymCount)
sym->SymCount = cls->CountCommands();
CommandCount += cls->CommandCount;
VariableCount += cls->VariableCount;
FunctionCount += cls->FunctionCount;
}
}
}
return CommandCount;
}
TAutoSymbol* TAutoClass::FindId(long id, ObjectPtr& obj)
{
TAutoSymbol* sym;
long cmdId;
if ((id <= 0) || !(AutoIds)) {
// reserved dispatch ID if negative or zero or AutoIDs is false
for (sym = Table; !sym->IsTerminator(); sym++) {
if (sym->TestFlag(asAnyCommand) && sym->DispId == id)
return sym;
if (sym->TestFlag(asClass)) {
ObjectPtr adjObj = sym->Convert(obj); // this pointer adjustment
TAutoSymbol* fsym = sym->GetClass()->FindId(id, adjObj);
if (fsym) {
obj = adjObj;
return fsym;
}
}
}
} else {
for (cmdId = 0, sym = Table; !sym->IsTerminator(); sym++) {
if (sym->TestFlag(asClass)) {
if (!sym->SymCount)
sym->SymCount = sym->GetClass()->CountCommands();
if (cmdId + sym->SymCount >= id) { // symbol in nested class
obj = sym->Convert(obj);
return sym->GetClass()->FindId(id-cmdId, obj);
}
cmdId += sym->SymCount;
}
else if (sym->TestFlag(asAnyCommand)) {
cmdId++;
if (cmdId == id) {
if (sym->DispId == -1)
return sym;
else
break;
}
}
}
}
return 0;
}
TAutoSymbol* TAutoClass::FindFunction(unsigned index, MEMBERID& retId)
{
TAutoSymbol* sym;
int funcCount = 0;
long cmdId = retId;
for (sym = Table; !sym->IsTerminator(); sym++) {
int attr = sym->GetFlags();
if (attr & asAnyCommand) {
cmdId++;
if ((attr & asOleType) != 0 && (attr & asGetSet) != asGetSet) {
if (funcCount++ == index) {
retId = (sym->DispId == -1L) ? cmdId : sym->DispId;
return sym;
}
}
} else if (sym->TestFlag(asClass)) {
TAutoClass* cls = sym->GetClass();
if (!sym->SymCount)
sym->SymCount = cls->CountCommands();
if (funcCount + cls->FunctionCount > index) {
retId = int(cmdId);
return cls->FindFunction(index - funcCount, retId);
}
funcCount += cls->FunctionCount;
cmdId += cls->CommandCount;
}
}
return 0; // should never happen unless caller overruns total count
}
TAutoSymbol* TAutoClass::FindVariable(unsigned index, MEMBERID& retId)
{
TAutoSymbol* sym;
int varCount = 0;
long cmdId = retId;
for (sym = Table; !sym->IsTerminator(); sym++) {
int attr = sym->GetFlags();
if (attr & asAnyCommand) {
cmdId++;
if ((attr & asGetSet) == asGetSet) {
if (varCount++ == index) {
retId = (sym->DispId == -1L) ? cmdId : sym->DispId;
return sym;
}
}
} else if (sym->TestFlag(asClass)) {
TAutoClass* cls = sym->GetClass();
if (!sym->SymCount)
sym->SymCount = cls->CountCommands();
if (varCount + cls->VariableCount > index) {
retId = int(cmdId);
return cls->FindVariable(index - varCount, retId);
}
varCount += cls->VariableCount;
cmdId += cls->CommandCount;
}
}
return 0; // should never happen unless caller overruns total count
}
short TAutoClass::GetArgCount(TAutoSymbol& sym)
{
short count = 0;
TAutoSymbol* arg = &sym;
while ((++arg)->TestFlag(asArgument))
count++;
return count;
}
TAutoSymbol* TAutoClass::Lookup(char far* name, TLangId lang, short symflags,
long far& retid)
{
long cmdId = 0;
for (TAutoSymbol* sym = Table; !sym->IsTerminator(); sym++) {
if (sym->TestFlag(asAnyCommand))
cmdId++;
if (sym->TestFlag(symflags) && sym->Name.Compare(name, lang) == 0) {
retid = sym->DispId == -1 ? cmdId : sym->DispId;
return sym;
}
else if (sym->TestFlag(asClass)) {
TAutoClass* cls = sym->GetClass();
if (!sym->SymCount)
sym->SymCount = cls->CountCommands();
long id;
TAutoSymbol* found = cls->Lookup(name, lang, symflags, id);
if (found) {
retid = id > 0 ? id + (long)cmdId : id;
return found;
}
cmdId += sym->SymCount;
}
}
return 0;
}
TAutoSymbol* TAutoClass::LookupArg(char far* name, TLangId lang,
TAutoSymbol* sym, long far& retid)
{
PRECONDITION(sym);
for (int i = 0; (++sym)->TestFlag(asArgument); ++i)
if (sym->Name.Compare(name, lang) == 0) {
retid = (long)i;
return sym;
}
return 0;
}
TXAuto::TError TAutoClass::Dispatch(ObjectPtr obj, TAutoCreator& creator,
TUnknown& owner, int attr,
TAutoStack& args, TAutoVal* retval)
{
TAutoCommand* cmdobj = 0;
TAutoIterator* iterator = 0;
try {
if (args.Symbol->IsIterator()) {
iterator = args.Symbol->BuildIter(obj, creator, owner, args.LangId);
iterator->SetSymbol(args.Symbol);
iterator->Init();
*retval = (IUnknown*)*iterator; // remains until RefCnt->0
} else {
cmdobj = args.Symbol->Build(obj, attr, args);
cmdobj->SetSymbol(args.Symbol);
if (args.ArgCount>0 && !cmdobj->Validate()) {// no validate for prop get
delete cmdobj;
return TXAuto::xValidateFailure;
}
cmdobj->Invoke();
if ((args.ErrorCode = cmdobj->Report()) != 0) {
args.ErrorMsg = TAutoCommand::LookupError(args.ErrorCode);
if (!args.ErrorMsg && args.Symbol) // if no error message available
args.ErrorMsg = args.Symbol->Name.Translate(args.LangId);
delete cmdobj;
return TXAuto::xErrorStatus;
}
if (retval) {
cmdobj->Return(*retval);
if (args.Symbol->IsEnum())
args.Symbol->GetEnum()->Convert(*retval, args.LangId);
TObjectDescriptor objDesc;
if (retval->GetObjDesc(objDesc)) {
if (!objDesc.Object) // null pointer returned from function
// there are three choices for behavior here:
// 1. Allow a dead object to be returned, fail when passed back
// 2. Fail now, however this prevents testing for null pointer
// 3. Return an empty variant, causing script to fail when used
*retval = TAutoVoid(); // return an empty value if no object
else
*retval = creator.CreateDispatch(objDesc);
}
}
delete cmdobj;
}
}
catch(TXAuto& xobj) {
delete cmdobj;
delete iterator;
return xobj.ErrorCode;
}
return TXAuto::xNoError;
}
TAutoClass::TExtLink::TExtLink(TClassList* list, HINSTANCE module)
: Classes(list), Module(module), Next(0)
{
for (Prev = &ClassList.Link; *Prev; Prev = &(*Prev)->Next)
; // link to end of list
}
TAutoClass::TExtLink::~TExtLink()
{
*Prev = Next;
if (Next)
Next->Prev = Prev;
}
//
//
//
int
TAutoClass::TClassList::CountAutoClasses()
{
int count = Count;
for (TExtLink* link = Link; link; link = link->Next)
count += link->Classes->CountAutoClasses();
return count;
}
//
//
//
TAutoClass::TAutoClassRef*
TAutoClass::TClassList::MergeAutoClasses(TAutoClass::TAutoClassRef* array)
{
for (TAutoClass* cls = List; cls; cls = cls->NextClass, array++)
array->Class = cls;
for (TExtLink* link = Link; link; link = link->Next)
array = link->Classes->MergeAutoClasses(array);
return array;
}
// ----------------------------------------------------------------------
// Helper routines
//
#if defined(BI_NAMESPACE)
namespace OCF {
#endif
//
//
TAutoCommand* _OCFFUNC
AutoQuitBuild(ObjectPtr obj, int/*attr*/, TAutoStack& args)
{
TServedObject& owner = *args.Owner;
// if the automation object is not in control of the app, execute a no-op
//
if (owner.Destruct == TObjectDescriptor::Quiet)
return new TAutoCommand(0);
// if registered as the active object, free it to release OLE's refcnt
//
if (owner.Creator.AppDesc.IsActiveObject(&owner))
owner.Creator.AppDesc.UnregisterObject();
// disconnect automation from app to prevent further access
//
owner.Object = 0;
owner.RootObject = 0;
// build command object for destructor, will either delete or PostQuitMsg
//
return owner.Class->GetDestructor()(obj, owner.Destruct);
}
#if defined(BI_NAMESPACE)
} // namespace OCF
#endif
//
// Temporary defines for using typeinfo with dynamic cast
//
void* __cdecl __DynamicCast(void* object, void* vtable,
void* srctyp, void* dsttyp,
int reference = 0);
struct tpid {int s; short m; short n; int VptrOffs; int Flags;}; // partial
#define CF_HAS_FARVPTR 0x1000
#if defined(BI_NAMESPACE)
namespace OCF {
#endif
//
//
const void*
_OCFFUNC DynamicCast(const void* obj, const typeinfo& src, const typeinfo& dst)
{
int vtblOff;
if (!obj)
return obj;
else if ((vtblOff = src.tpp->VptrOffs) == -1)
return src==dst ? obj : 0;
else if (src.tpp->Flags & CF_HAS_FARVPTR)
return __DynamicCast(const_cast<void far*>(obj),
*(void far**)((char*)obj+vtblOff), src.tpp, dst.tpp);
else
return __DynamicCast(const_cast<void far*>(obj),
*(void near**)((char*)obj+vtblOff), src.tpp,dst.tpp);
}
//
//
const void far*
MostDerived(const void far* obj, const typeinfo& src)
{
int vtblOff;
if (!obj || (vtblOff = src.tpp->VptrOffs) == -1)
return obj;
else if (src.tpp->Flags & CF_HAS_FARVPTR)
return __DynamicCast(const_cast<void far*>(obj),
*(void far**)((char*)obj+vtblOff), src.tpp, 0);
else
return __DynamicCast(const_cast<void far*>(obj),
*(void near**)((char*)obj+vtblOff), src.tpp, 0);
}
#if defined(BI_NAMESPACE)
} // namespace OCF
#endif
//____________________________________________________________________________
//
// TAutoCommand implementation - inlined to allow definition of _AUTOCLASS
//____________________________________________________________________________
#if defined(BI_NAMESPACE)
namespace OCF {
#endif
TAutoCommand::TErrorMsgHook _OCFDATA TAutoCommand_ErrorLookup = 0; // module static
TAutoCommand::TCommandHook _OCFDATA TAutoCommand_InvokeHook = 0; // module static
#if defined(BI_NAMESPACE)
} // namespace OCF
#endif